// Fhourstones 3.0 Board Logic
// (http://www.cwi.nl/~tromp/c4/fhour.html)
//
// implementation of the well-known game
// usually played on a vertical board of 7 columns by 6 rows,
// where 2 players take turns in dropping counters in a column.
// the first player to get four of his counters
// in a horizontal, vertical or diagonal row, wins the game.
// if neither player has won after 42 moves, then the game is drawn.
//
// This software is copyright (c) 1996-2008 by
//      John Tromp
//      600 Route 25A
//      East Setauket
//      NY 11733
// E-mail: john.tromp@gmail.com
//
// This notice must not be removed.
// This software must not be sold for profit.
// You may redistribute if your distributees have the
// same rights and restrictions.

//Modified by:

/***********************************************************************
 ** Reykjavik University
 ** Grímur Tómasson & Eiríkur Torfason
 ** Copyright (c) 2011. All rights reserved.
 **********************************************************************/

#include "bitboard.h"

#include <iostream>

//----------------------------------------------------------------------------------------------------------
const char EMPTY_CELL_ALIAS = '.';
//----------------------------------------------------------------------------------------------------------
//Global variables from original code, not used as such since we parameter pass everything

bitboard color[2];  // black and red bitboard (one board for each color)
int moves[SIZE]; // Move history
int nplies; // The current turn number (starting at 0)
char height[WIDTH]; // Holds bit index of lowest free square in each column
//----------------------------------------------------------------------------------------------------------
//Functions

void reset()
{
	nplies = 0;
	color[0] = color[1] = 0;
	for (int i=0; i<WIDTH; i++)
	{
		height[i] = (char)(H1*i);
	}
}
//----------------------------------------------------------------------------------------------------------

bitboard positioncode()
{
	return color[nplies&1] + color[0] + color[1] + BOTTOM;
}
//----------------------------------------------------------------------------------------------------------

void printMoves()
{	
	for (int i=0; i<nplies; i++)
	{
		printf("%d ", 1+moves[i]);
	}
}
//----------------------------------------------------------------------------------------------------------

// return whether newboard lacks overflowing column
int isLegal(bitboard newboard)
{
	return (newboard & TOP) == 0;
}
//----------------------------------------------------------------------------------------------------------

// return whether columns col has room
int isPlayable(int col)
{
	return isLegal(color[nplies&1] | ((bitboard)1 << height[col]));
}
//----------------------------------------------------------------------------------------------------------

// return non-zero iff newboard includes a win
bitboard hasWon(bitboard newboard)
{
	bitboard diag1 = newboard & (newboard>>HEIGHT);
	bitboard hori = newboard & (newboard>>H1);
	bitboard diag2 = newboard & (newboard>>H2);
	bitboard vert = newboard & (newboard>>1);
	return ((diag1 & (diag1 >> 2*HEIGHT)) |
			(hori & (hori >> 2*H1)) |
			(diag2 & (diag2 >> 2*H2)) |
			(vert & (vert >> 2)));
}
//----------------------------------------------------------------------------------------------------------

// return whether newboard is legal and includes a win
int isLegalHasWon(bitboard newboard)
{
	return isLegal(newboard) && hasWon(newboard);
}
//----------------------------------------------------------------------------------------------------------

void undoMove()
{	
	int n = moves[--nplies];
	color[nplies&1] ^= (bitboard)1<<--height[n];
}
//----------------------------------------------------------------------------------------------------------

void makeMove(int n) 
{
	color[nplies&1] ^= (bitboard)1<<height[n]++;
	moves[nplies++] = n;
}
//----------------------------------------------------------------------------------------------------------

//Added by GT & EFT

void move( int column )
{
	//
	// Bounds check
	//
	if( column < 0 || column > 6 )
	{
		std::cout << "Column range is from a-g!" << std::endl;
		return;
	}
	//
	// Check whether move is valid
	//
	if( !isPlayable( column ) )
	{
		std::cout << "Illegal move, column: " << column << std::endl;
		return;
	}
	//
	// Make the move
	//
	int side = (nplies&1);
	makeMove( column );
	//
	// Game over?
	//
	if( hasWon( color[side] ) )
	{
		std::cout << "Player: " << side << " has won!" << std::endl;
	}	
}
//----------------------------------------------------------------------------------------------------------

int* ply() 
{ 
	return &nplies; 
}
//----------------------------------------------------------------------------------------------------------

bitboard* colorPointer(int index) 
{ 
	return &color[index]; 
}
//----------------------------------------------------------------------------------------------------------

bitboard checkBit( bitboard board, bitboard position )
{
	bitboard bitboardOne = 1;
	return board & (bitboardOne << position);
}
//----------------------------------------------------------------------------------------------------------
//
// Clones the supplied board and places a token in the specified column
//
bitboard newBoardAndMove( bitboard original, int column )
{
	return original | (bitboard)1 << height[column];
}
//----------------------------------------------------------------------------------------------------------
//
// Get's the bitboard index for the cell at the given coordinates.
//
int getCellIndex(int column, int row)
{
	return row + column * 7;
}
//----------------------------------------------------------------------------------------------------------
//
// Returns 'B', 'R' or '.' depending on whether the cell with the specified index contains a Black token,
// Red token or no token respectively.
//
char getSymbol( const bitboard bboard1, const bitboard bboard2, int index )
{
	if( CHECK_BIT( bboard1, index ) > 0 )
	{
		return COLOR_O_ALIAS;
	}
	if( CHECK_BIT( bboard2, index ) > 0 )
	{
		return COLOR_1_ALIAS;
	}
	return EMPTY_CELL_ALIAS;
}
//----------------------------------------------------------------------------------------------------------
//
// Displays the current state of the game board in a somewhat human-friendly format
//
void printStatus()
{
	printf( "\n    a b c d e f g\n" );
	printf( "-----------------\n" );
	int prefix = 6;
	for( int rows = 5; rows > -1; --rows )
	{
		printf( "%i | ", prefix );
		for( int column = 0; column < 48; column += 7 )
		{
			printf( "%c ", getSymbol( color[0], color[1], column + rows ));
		}
		printf( "\n" );
		--prefix;
	}
	printf( "\n" );
}
//----------------------------------------------------------------------------------------------------------
//
// Displays the current state of the board in a format understood by the game master server
//
void printStatusInline()
{
	int side = nplies&1;
	char whosTurn = side ? COLOR_1_ALIAS : COLOR_O_ALIAS;
	printf( "%c", whosTurn );
	
	for (int row = 0; row < HEIGHT; ++row)
	{
		for (int column = 0; column < WIDTH; ++column)
		{
			char symbol = getSymbol( color[0], color[1], getCellIndex( column, row ) );
			printf("%c", symbol);
		}
	}
	printf("\n");  //is this done in the java code?
}
//----------------------------------------------------------------------------------------------------------

void printDebug(bitboard board)
{
	for( bitboard i = 0; i < 64; ++i)
	{
		printf("%i", checkBit( board, i ) != 0 ? 1 : 0 );
	}
	printf("\n");
}
//----------------------------------------------------------------------------------------------------------

int firstLegalMove()
{
	for( int i = 0; i < WIDTH; ++i )
	{
		if( isPlayable( i ) )
		{
			return i;
		}
	}
	return 0; //No legal moves (games up, detected elsewhere).  
}
//----------------------------------------------------------------------------------------------------------
